package com.gwl.concurrent.interval;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import static java.lang.System.out; 

class TaskPortion implements Runnable {

	private static final AtomicInteger COUNTER = new AtomicInteger(0); 
	
	private int id = COUNTER.incrementAndGet();  
	private CountDownLatch latch; 
	Random rand = new Random(47); 
	TaskPortion(CountDownLatch l) { 
		latch = l; 
	} 
	
	@Override
	public void run() { 
		try {
			doWork();
			latch.countDown(); 
		} catch (InterruptedException e) {
			// Acceptable way to exit 
		} 
	} 
	
	public void doWork() throws InterruptedException { 
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000)); 
		out.println(this + "completed "); 
	}
	public String toString() { 
		return String.format("%1$-3d ", id); 
	}
}

class WaitingTask implements Runnable { 
	private static final AtomicInteger COUNTER = new AtomicInteger(0); 

	private int id = COUNTER.incrementAndGet();  
	private CountDownLatch latch; 
	WaitingTask(CountDownLatch l) { 
		latch = l; 
	}
	
	@Override
	public void run() {
		try {
			latch.await(); 
			out.println("Latch barrier passed for " + this); 
		} catch (InterruptedException e) {
			out.println(this + " interrupted "); 
		} 
	} 
	public String toString() { 
		return String.format("WaitintTask %1$-3d ", id); 
	}
}

public class CountDownLatchDemo {
	static final int SIZE = 100; 
	public static void main(String[] args) {
		ExecutorService exec = Executors.newCachedThreadPool(); 
		// All must share a single CountDownLatch object:
		CountDownLatch latch = new CountDownLatch(SIZE); 
		for(int i = 0; i < 10; i++)  
			exec.execute(new WaitingTask(latch)); 
		for(int i=0; i<SIZE; i++)  
			exec.execute(new TaskPortion(latch)); 
		out.println("latched all tasks"); 
		exec.shutdown();  // Quit when all tasks complete
	}
} /* Execute to see output */
